package test.studyjdk.thread.procom;

import java.util.LinkedList;

public class WaitAndNotifyP {

    private final int MAX_SIZE = 10;

    private LinkedList<Object> list = new LinkedList<>();

    public void produce() {
        synchronized (list) {
            if (list.size() > MAX_SIZE) {
                System.out.println("【生产者" + Thread.currentThread().getName() + "】仓库已满");
                try {
                    list.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            list.add(new Object());
            System.out.println("【生产者" + Thread.currentThread().getName() + "】生产一个产品，现库存" + list.size());
            list.notifyAll();
        }
    }

    public void consume() {
        synchronized (list) {
            while (list.size() == 0) {
                System.out.println("【消费者" + Thread.currentThread().getName() + "】仓库为空");
                try {
                    list.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            list.remove();
            System.out.println("【消费者" + Thread.currentThread().getName() + "】消费一个产品，现库存" + list.size());
            list.notifyAll();
        }
    }

    public static void main(String[] args) {
        WaitAndNotifyP waitAndNotifyP = new WaitAndNotifyP();
        Thread p1 = new Thread(new P(waitAndNotifyP));
        Thread p2 = new Thread(new P(waitAndNotifyP));
        Thread p3 = new Thread(new P(waitAndNotifyP));

        Thread c1 = new Thread(new C(waitAndNotifyP));
        Thread c2 = new Thread(new C(waitAndNotifyP));

        p1.start();
        p2.start();
        p3.start();
        c1.start();
        c2.start();
    }

}

class P implements Runnable {

    private WaitAndNotifyP waitAndNotifyP;

    public P(WaitAndNotifyP waitAndNotifyP) {
        this.waitAndNotifyP = waitAndNotifyP;
    }

    @Override
    public void run() {
        while (true) {
            try {
                Thread.sleep(1000);
                waitAndNotifyP.produce();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}

class C implements Runnable {
    private WaitAndNotifyP waitAndNotifyP;

    public C(WaitAndNotifyP waitAndNotifyP) {
        this.waitAndNotifyP = waitAndNotifyP;
    }

    /*
     * (non-Javadoc)
     * 
     * @see java.lang.Runnable#run()
     */
    @Override
    public void run() {
        while (true) {
            try {
                Thread.sleep(2000);
                waitAndNotifyP.consume();
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

    }

}

class Main {
    public static void main(String[] args) {
        WaitAndNotifyP waitAndNotifyP = new WaitAndNotifyP();
        Thread p1 = new Thread(new P(waitAndNotifyP));
        Thread p2 = new Thread(new P(waitAndNotifyP));
        Thread p3 = new Thread(new P(waitAndNotifyP));

        Thread c1 = new Thread(new C(waitAndNotifyP));
        Thread c2 = new Thread(new C(waitAndNotifyP));

        p1.start();
        p2.start();
        p3.start();
        c1.start();
        c2.start();
    }
}
